from threading import Thread, Lock
from decimal import Decimal, InvalidOperation
from extensions import db
from flask import (
    Flask,
    flash,
    Blueprint,
    current_app,
    render_template,
    request,
    redirect,
    url_for,
    jsonify,
    copy_current_request_context,
)
from flask_login import login_required, current_user, logout_user
from models import (
    Product,
    ProductDetail,
    ImageRecord,
    Company,
    User,
    Role,
    ExchangeRate,
    Currency,
    Permission,
)

# from flask_wtf.csrf import csrf_exempt  # 导入豁免装饰器
import requests
from urllib.parse import urlparse
from datetime import datetime, date
import time
import json
import re
import os
from pathlib import Path
from flask_migrate import Migrate
from config import headers
from sqlalchemy import func
from sqlalchemy.exc import IntegrityError
from download_service import download_images_async, download_single_image
from export import export_bp, data_bp
from utils import process_url_data
from werkzeug.security import generate_password_hash
from flask_login import LoginManager
from cart_routes import cart_bp
from werkzeug.utils import secure_filename
import uuid
from log_config import logger
from extensions import image_path_format, images_url_replace
from decouple import config
from flask_apscheduler import APScheduler
from get_huilv import crawl_exchange_rate

download_lock = Lock()

app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///data.db"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.secret_key = config("SECRET_KEY")
# app.config["JOBS"] = [
#     {
#         "id": "check_and_crawl",
#         "func": "app:check_and_crawl_task",
#         "trigger": "cron",
#         "hour": 9,  # 每天凌晨2点执行
#         "minute": 0,
#     }
# ]

db.init_app(app)
migrate = Migrate(app, db)
scheduler = APScheduler()

# 配置图片存储路径（使用pathlib处理）
IMAGE_FOLDER = Path("static") / "images"
IMAGE_FOLDER.mkdir(parents=True, exist_ok=True)

app.register_blueprint(export_bp)
app.register_blueprint(data_bp)
app.register_blueprint(cart_bp)

# 初始化 Flask-Login


login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = "login"  # 未登录时重定向到登录页面


def check_and_crawl():
    with app.app_context():
        today = date.today()
        exists = db.session.query(
            db.exists().where(ExchangeRate.collected_date == today)
        ).scalar()
        if exists:
            logger.info(f"✅ 数据已存在：{today}")
        else:
            logger.warning(f"⚠️ 未找到今日数据，开始爬取：{today}")
            crawl_exchange_rate()
            logger.success("✅ 爬取并写入完成")


# 🧭 添加定时任务
scheduler.add_job(
    id="crawl_9am", func=check_and_crawl, trigger="cron", hour=9, minute=0
)
scheduler.add_job(
    id="crawl_2pm", func=check_and_crawl, trigger="cron", hour=14, minute=0
)
scheduler.add_job(
    id="crawl_4pm", func=check_and_crawl, trigger="cron", hour=16, minute=0
)
# 初始化调度器
scheduler.init_app(app)
scheduler.start()


# 加在 app.py 的某处（比如 scheduler.start() 后）
scheduler.add_job(
    id="daily_crawl_check", func=check_and_crawl, trigger="cron", hour=10, minute=0
)


@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))


def init_currencies():
    """初始化常用货币数据"""
    currencies_data = [
        # 主要国际货币
        {
            "code": "CNY",
            "symbol": "¥",
            "name_cn": "人民币",
            "name_en": "Chinese Yuan",
            "name_local": "元",
        },
        {
            "code": "USD",
            "symbol": "$",
            "name_cn": "美元",
            "name_en": "US Dollar",
            "name_local": "dollar",
        },
        {
            "code": "EUR",
            "symbol": "€",
            "name_cn": "欧元",
            "name_en": "Euro",
            "name_local": "euro",
        },
        {
            "code": "JPY",
            "symbol": "¥",
            "name_cn": "日元",
            "name_en": "Japanese Yen",
            "name_local": "円",
        },
        {
            "code": "GBP",
            "symbol": "£",
            "name_cn": "英镑",
            "name_en": "British Pound",
            "name_local": "pound",
        },
        {
            "code": "AUD",
            "symbol": "$",
            "name_cn": "澳大利亚元",
            "name_en": "Australian Dollar",
            "name_local": "dollar",
        },
        {
            "code": "CAD",
            "symbol": "$",
            "name_cn": "加拿大元",
            "name_en": "Canadian Dollar",
            "name_local": "dollar",
        },
        {
            "code": "CHF",
            "symbol": "Fr",
            "name_cn": "瑞士法郎",
            "name_en": "Swiss Franc",
            "name_local": "Franken",
        },
        {
            "code": "HKD",
            "symbol": "$",
            "name_cn": "港币",
            "name_en": "Hong Kong Dollar",
            "name_local": "港幣",
        },
        {
            "code": "SGD",
            "symbol": "$",
            "name_cn": "新加坡元",
            "name_en": "Singapore Dollar",
            "name_local": "dollar",
        },
        # 国际贸易常用货币
        {
            "code": "RUB",
            "symbol": "₽",
            "name_cn": "俄罗斯卢布",
            "name_en": "Russian Ruble",
            "name_local": "рубль",
        },
        {
            "code": "AED",
            "symbol": "د.إ",
            "name_cn": "阿联酋迪拉姆",
            "name_en": "UAE Dirham",
            "name_local": "درهم",
        },
        {
            "code": "SAR",
            "symbol": "ر.س",
            "name_cn": "沙特里亚尔",
            "name_en": "Saudi Riyal",
            "name_local": "ريال",
        },
        {
            "code": "TRY",
            "symbol": "₺",
            "name_cn": "土耳其里拉",
            "name_en": "Turkish Lira",
            "name_local": "Türk lirası",
        },
        {
            "code": "KRW",
            "symbol": "₩",
            "name_cn": "韩国元",
            "name_en": "South Korean Won",
            "name_local": "원",
        },
    ]

    # 检查是否已初始化过
    if Currency.query.first() is not None:
        return False  # 已初始化过

    try:
        # 批量创建货币记录
        for currency_info in currencies_data:
            currency = Currency(
                code=currency_info["code"],
                symbol=currency_info["symbol"],
                name_cn=currency_info["name_cn"],
                name_en=currency_info["name_en"],
                name_local=currency_info["name_local"],
                is_active=True,
            )
            db.session.add(currency)

        db.session.commit()
        return True
    except Exception as e:
        db.session.rollback()
        print(f"初始化货币数据失败: {str(e)}")
        return False


def extract_filename_from_url(url):
    """从URL中提取原始文件名，使用pathlib处理路径"""
    try:
        path = urlparse(url).path
        filename = os.path.basename(path)

        if not filename or filename == "/":
            return f"image_{datetime.now().strftime('%Y%m%d%H%M%S')}.jpg"

        # 替换非法文件名字符
        invalid_chars = r'[<>:"/\\|?*]'
        filename = re.sub(invalid_chars, "_", filename)

        if not filename.strip():
            return f"image_{datetime.now().strftime('%Y%m%d%H%M%S')}.jpg"

        return filename
    except Exception as e:
        print(f"文件名提取失败: {str(e)}")
        return f"image_{datetime.now().strftime('%Y%m%d%H%M%S')}.jpg"


def download_image(image_url, detail_id):
    try:
        filename = extract_filename_from_url(image_url)
        local_path = IMAGE_FOLDER / filename

        # 检查是否已存在该URL的下载记录
        existing_records = ImageRecord.query.filter_by(
            detail_id=detail_id, image_url=image_url
        ).all()
        if existing_records:
            existing_path = Path(existing_records[0].local_path)
            if existing_path.exists():
                # 更新ProductDetail表的local_image_path字段
                detail = ProductDetail.query.get(detail_id)
                if detail:
                    existing_path = image_path_format(existing_path)
                    detail.local_image_path = existing_path
                    db.session.commit()
                return True, existing_path

        # 下载图片
        response = requests.get(image_url, headers=headers, timeout=15)
        if response.status_code == 200:
            with open(local_path, "wb") as f:
                for chunk in response.iter_content(1024):
                    f.write(chunk)
            local_path = image_path_format(local_path)
            # 保存记录到ImageRecord表
            image_record = ImageRecord(
                detail_id=detail_id,
                image_url=image_url,
                local_path=local_path,
            )
            db.session.add(image_record)

            # 更新ProductDetail表的local_image_path字段
            detail = ProductDetail.query.get(detail_id)
            if detail:
                local_path = image_path_format(local_path)
                detail.local_image_path = local_path
                db.session.commit()

            return True, local_path
        else:
            return False, f"下载失败: HTTP状态码 {response.status_code}"
    except Exception as e:
        return False, f"下载失败: {str(e)}"


@app.route("/download_images/<int:product_id>", methods=["POST"])
@login_required
def download_images(product_id):
    # 检查用户是否有下载图片的权限
    if not current_user.has_permission("download_images"):
        flash("您没有权限下载图片", "danger")
        return jsonify({"status": "error", "message": "无权限"})

    with app.app_context():
        details = ProductDetail.query.filter_by(product_id=product_id).all()
        detail_ids = [d.id for d in details if d.image_url and not d.local_image_path]

    # 异步后台任务
    thread = Thread(target=download_images_async, args=(app, detail_ids))
    thread.start()

    return jsonify({"status": "started", "count": len(detail_ids)})


def scan_and_add_missing_images():
    # 使用pathlib获取static/images目录路径
    images_dir = Path(app.root_path) / "static" / "images"

    # 获取数据库中所有已记录的图片文件名（去掉路径，只保留文件名）
    db_images = set()
    for detail in ProductDetail.query.filter(
        ProductDetail.local_image_path.isnot(None)
    ).all():
        if detail.local_image_path:
            # 去除路径中的/static/前缀（如果存在）
            path = detail.local_image_path.replace("/static/", "")
            db_images.add(Path(path).name)

    # 扫描static/images目录
    missing_count = 0
    for filepath in images_dir.iterdir():
        # 检查是否是文件且不在数据库中
        if filepath.is_file() and filepath.name not in db_images:
            # 查找是否有对应的ProductDetail记录（根据URL末尾匹配）
            matching_detail = ProductDetail.query.filter(
                ProductDetail.image_url.endswith(filepath.name)
            ).first()

            if matching_detail:
                # 创建本地路径（不再包含/static/前缀）
                local_path = f"images/{filepath.name}"
                local_path = image_path_format(local_path)
                # 更新ProductDetail记录
                matching_detail.local_image_path = local_path

                # 添加ImageRecord记录
                image_record = ImageRecord(
                    detail_id=matching_detail.id,
                    image_url=matching_detail.image_url,
                    local_path=local_path,
                    download_time=datetime.now(),
                )
                db.session.add(image_record)
                missing_count += 1

    db.session.commit()
    return missing_count


@app.route("/download_images/all", methods=["POST"])
@login_required
def download_all_images():
    # 检查用户是否有批量下载图片的权限
    if not current_user.has_permission("download_all_images"):
        flash("您没有权限执行批量下载", "danger")
        return jsonify({"status": "error", "message": "无权限"})

    with app.app_context():
        # 第一步：清理已记录但本地文件不存在的记录
        details_all = ProductDetail.query.filter(
            ProductDetail.image_url.isnot(None)
        ).all()
        repaired_count = 0
        for d in details_all:
            if d.local_image_path:
                # 处理路径中的/static/前缀（如果存在）
                clean_path = image_path_format(d.local_image_path)
                # 使用pathlib检查文件是否存在
                file_path = Path(app.root_path) / "static" / clean_path
                if not file_path.exists():
                    # 删除 ImageRecord 中的记录
                    db.session.query(ImageRecord).filter_by(
                        detail_id=d.id, local_path=d.local_image_path
                    ).delete()

                    # 清空 local_image_path 字段
                    d.local_image_path = None
                    repaired_count += 1

        db.session.commit()
        # 第二步：扫描并添加缺失的记录
        added_count = scan_and_add_missing_images()
        repaired_count += added_count

        # 第三步：找出还未下载的记录
        details_pending = ProductDetail.query.filter(
            ProductDetail.image_url.isnot(None),
            ProductDetail.local_image_path.is_(None),
        ).all()
        detail_imgs = [d.image_url for d in details_pending]
        detail_ids = [d.id for d in details_pending]

    # 异步执行批量下载
    thread = Thread(target=download_images_async, args=(app, detail_ids))
    thread.start()

    return jsonify(
        {
            "status": "started",
            "count": repaired_count,
            "detail_imgs": detail_imgs,
            "to_download": len(detail_ids),
        }
    )


def batch_download_images(detail_ids):
    """批量下载任务"""
    total = len(detail_ids)
    success_count = 0
    failed_count = 0
    failed_list = []

    with app.app_context():
        for i, detail_id in enumerate(detail_ids):
            details = ProductDetail.query.get(detail_id)
            if details and details.image_url:
                with download_lock:
                    success, message = download_image(details.image_url, detail_id)
                    if success:
                        success_count += 1
                    else:
                        failed_count += 1
                        failed_list.append(
                            {
                                "detail_id": detail_id,
                                "image_url": details.image_url,
                                "error": message,
                            }
                        )
            time.sleep(0.3)
            if i % 10 == 0:
                db.session.commit()

    db.session.commit()
    print(f"下载统计: 总数{total}, 成功{success_count}, 失败{failed_count}")


def get_best_prices(product):
    # 初始化默认属性（处理无详情的情况）
    product.min_price = 0.0
    product.max_price = 0.0
    product.min_moq = 1
    product.moqs = [1]
    product.spec_count = 0

    if product.details:
        first_detail = product.details[0]
        # 修复图片路径处理逻辑
        if first_detail.local_image_path:
            full_local_path = os.path.join(
                current_app.root_path, "static", first_detail.local_image_path
            )
            if os.path.exists(full_local_path):
                first_detail.display_image_url = first_detail.local_image_path
            else:
                first_detail.display_image_url = first_detail.image_url
        else:
            first_detail.display_image_url = first_detail.image_url

        # 获取所有批发价格信息
        all_prices = [
            float(price.price)
            for detail in product.details
            for price in detail.wholesale_prices
        ] + [detail.price for detail in product.details if detail.price is not None]
        moqs = {
            price.min_quantity
            for detail in product.details
            for price in detail.wholesale_prices
        }

        # 计算价格范围和最小起订量
        if all_prices:
            product.min_price = min(all_prices)
            product.max_price = max(all_prices)
            product.min_moq = min(moqs) if moqs else 1
            product.moqs = sorted(moqs) if moqs else [1]
            product.spec_count = len(product.details)
        else:
            # 如果没有价格数据，使用默认值
            product.min_price = 0.0
            product.max_price = 0.0
            product.min_moq = 1
            product.moqs = [1]
            product.spec_count = len(product.details)

    return product


# 登录路由
@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "POST":
        username = request.form["username"]
        password = request.form["password"]
        user = User.query.filter_by(username=username).first()
        if user and user.check_password(password):
            from flask_login import login_user

            login_user(user)
            return redirect(url_for("list_main"))
        else:
            flash("用户名或密码错误", "danger")
    return render_template("login.html")


# 退出登录
@app.route("/logout")
@login_required
def logout():
    logout_user()
    return redirect(url_for("login"))


@app.route("/admin/manage", methods=["GET"])
@login_required
def admin_manage():
    # 检查是否为超级管理员
    admin_role = Role.query.filter_by(name="超级管理员").first()
    if not admin_role or admin_role not in current_user.roles:
        flash("只有超级管理员可以访问此页面", "danger")
        return redirect(url_for("index"))

    users = User.query.all()
    # 为每个用户添加 role_names 属性
    for user in users:
        user.role_names = ", ".join([role.name for role in user.roles]) or "无角色"

    roles = Role.query.all()
    # 为每个角色添加 permissions_names 属性
    for role in roles:
        role.permissions_names = (
            ", ".join([perm.name for perm in role.permissions]) or "无权限"
        )

    permissions = Permission.query.all()
    return render_template(
        "users/admin_manage.html", users=users, roles=roles, permissions=permissions
    )


@app.route("/admin/user/add", methods=["GET", "POST"])
@login_required
def add_user():
    admin_role = Role.query.filter_by(name="超级管理员").first()
    if not admin_role or admin_role not in current_user.roles:
        flash("只有超级管理员可以添加用户", "danger")
        return redirect(url_for("admin_manage"))

    if request.method == "POST":
        username = request.form["username"].strip()
        password = request.form["password"].strip()
        if not username or not password:
            flash("用户名和密码不能为空", "danger")
            return redirect(url_for("add_user"))

        user = User(
            username=username,
            password_hash=generate_password_hash(password),
            name_cn=request.form.get("name_cn", ""),
            name_en=request.form.get("name_en", ""),
            phone=request.form.get("phone", ""),
            email=request.form.get("email", ""),
            is_active=request.form.get("is_active") == "on",
        )

        # 处理角色关联
        role_ids = request.form.getlist("roles")
        for role_id in role_ids:
            role = Role.query.get(role_id)
            if role:
                user.roles.append(role)

        # 处理直接权限关联
        permission_ids = request.form.getlist("permissions")
        for permission_id in permission_ids:
            permission = Permission.query.get(permission_id)
            if permission:
                user.permissions.append(permission)

        db.session.add(user)
        db.session.commit()
        flash("用户添加成功", "success")
        return redirect(url_for("admin_manage"))

    roles = Role.query.all()
    permissions = Permission.query.all()
    return render_template("users/add_user.html", roles=roles, permissions=permissions)


@app.route("/admin/user/edit/<int:id>", methods=["GET", "POST"])
@login_required
def edit_user(id):
    admin_role = Role.query.filter_by(name="超级管理员").first()
    if not admin_role or admin_role not in current_user.roles:
        flash("只有超级管理员可以编辑用户", "danger")
        return redirect(url_for("admin_manage"))

    user = User.query.get_or_404(id)
    if request.method == "POST":
        user.username = request.form["username"].strip() or user.username
        password = request.form.get("password", "").strip()
        if password:
            user.password_hash = generate_password_hash(password)
        user.name_cn = request.form.get("name_cn", "")
        user.name_en = request.form.get("name_en", "")
        user.phone = request.form.get("phone", "")
        user.email = request.form.get("email", "")
        user.is_active = request.form.get("is_active") == "on"

        # 更新角色关联
        user.roles = []
        role_ids = request.form.getlist("roles")
        for role_id in role_ids:
            role = Role.query.get(role_id)
            if role:
                user.roles.append(role)

        # 更新直接权限关联
        user.permissions = []
        permission_ids = request.form.getlist("permissions")
        for permission_id in permission_ids:
            permission = Permission.query.get(permission_id)
            if permission:
                user.permissions.append(permission)

        db.session.commit()
        flash("用户更新成功", "success")
        return redirect(url_for("admin_manage"))

    roles = Role.query.all()
    permissions = Permission.query.all()
    return render_template(
        "users/edit_user.html", user=user, roles=roles, permissions=permissions
    )


@app.route("/admin/user/delete/<int:id>")
@login_required
def delete_user(id):
    admin_role = Role.query.filter_by(name="超级管理员").first()
    if not admin_role or admin_role not in current_user.roles:
        flash("只有超级管理员可以删除用户", "danger")
        return redirect(url_for("admin_manage"))

    user = User.query.get_or_404(id)
    if user.id == current_user.id:
        flash("不能删除当前登录用户", "danger")
    else:
        db.session.delete(user)
        db.session.commit()
        flash("用户删除成功", "success")
    return redirect(url_for("admin_manage"))


@app.route("/admin/role/add", methods=["GET", "POST"])
@login_required
def add_role():
    admin_role = Role.query.filter_by(name="超级管理员").first()
    if not admin_role or admin_role not in current_user.roles:
        flash("只有超级管理员可以添加角色", "danger")
        return redirect(url_for("admin_manage"))

    if request.method == "POST":
        name = request.form["name"].strip()
        if not name:
            flash("角色名称不能为空", "danger")
            return redirect(url_for("add_role"))

        role = Role(name=name)
        permission_ids = request.form.getlist("permissions")
        for perm_id in permission_ids:
            perm = Permission.query.get(perm_id)
            if perm:
                role.permissions.append(perm)

        db.session.add(role)
        db.session.commit()
        flash("角色添加成功", "success")
        return redirect(url_for("admin_manage"))

    permissions = Permission.query.all()
    return render_template("users/add_role.html", permissions=permissions)


@app.route("/admin/role/edit/<int:id>", methods=["GET", "POST"])
@login_required
def edit_role(id):
    admin_role = Role.query.filter_by(name="超级管理员").first()
    if not admin_role or admin_role not in current_user.roles:
        flash("只有超级管理员可以编辑角色", "danger")
        return redirect(url_for("admin_manage"))

    role = Role.query.get_or_404(id)
    if request.method == "POST":
        role.name = request.form["name"].strip() or role.name
        role.permissions = []
        permission_ids = request.form.getlist("permissions")
        for perm_id in permission_ids:
            perm = Permission.query.get(perm_id)
            if perm:
                role.permissions.append(perm)

        db.session.commit()
        flash("角色更新成功", "success")
        return redirect(url_for("admin_manage"))

    permissions = Permission.query.all()
    return render_template("users/edit_role.html", role=role, permissions=permissions)


@app.route("/admin/role/delete/<int:id>")
@login_required
def delete_role(id):
    admin_role = Role.query.filter_by(name="超级管理员").first()
    if not admin_role or admin_role not in current_user.roles:
        flash("只有超级管理员可以删除角色", "danger")
        return redirect(url_for("admin_manage"))

    role = Role.query.get_or_404(id)
    if role.name == "超级管理员":
        flash("不能删除超级管理员角色", "danger")
    else:
        db.session.delete(role)
        db.session.commit()
        flash("角色删除成功", "success")
    return redirect(url_for("admin_manage"))


@app.route("/admin/permission/add", methods=["GET", "POST"])
@login_required
def add_permission():
    admin_role = Role.query.filter_by(name="超级管理员").first()
    if not admin_role or admin_role not in current_user.roles:
        flash("只有超级管理员可以添加权限", "danger")
        return redirect(url_for("admin_manage"))

    if request.method == "POST":
        codename = request.form["codename"].strip()
        name = request.form["name"].strip()
        content_type = request.form["content_type"].strip()
        if not codename or not name or not content_type:
            flash("所有字段均为必填", "danger")
            return redirect(url_for("add_permission"))

        permission = Permission(codename=codename, name=name, content_type=content_type)
        db.session.add(permission)
        db.session.commit()
        flash("权限添加成功", "success")
        return redirect(url_for("admin_manage"))

    return render_template("users/add_permission.html")


@app.route("/admin/permission/edit/<int:id>", methods=["GET", "POST"])
@login_required
def edit_permission(id):
    admin_role = Role.query.filter_by(name="超级管理员").first()
    if not admin_role or admin_role not in current_user.roles:
        flash("只有超级管理员可以编辑权限", "danger")
        return redirect(url_for("admin_manage"))

    permission = Permission.query.get_or_404(id)
    if request.method == "POST":
        permission.codename = request.form["codename"].strip() or permission.codename
        permission.name = request.form["name"].strip() or permission.name
        permission.content_type = (
            request.form["content_type"].strip() or permission.content_type
        )
        db.session.commit()
        flash("权限更新成功", "success")
        return redirect(url_for("admin_manage"))

    return render_template("users/edit_permission.html", permission=permission)


@app.route("/admin/permission/delete/<int:id>")
@login_required
def delete_permission(id):
    admin_role = Role.query.filter_by(name="超级管理员").first()
    if not admin_role or admin_role not in current_user.roles:
        flash("只有超级管理员可以删除权限", "danger")
        return redirect(url_for("admin_manage"))

    permission = Permission.query.get_or_404(id)
    db.session.delete(permission)
    db.session.commit()
    flash("权限删除成功", "success")
    return redirect(url_for("admin_manage"))


@app.route("/")
def index():
    return redirect(url_for("list_main"))


@app.route("/main", defaults={"page": 1})
@app.route("/main/page/<int:page>")
@login_required
def list_main(page):
    try:
        # 确保 page 有效，防止负数或过大值
        if page < 1:
            page = 1

        # 每页显示50条数据，按ID降序排列
        if Role.query.filter_by(name="超级管理员").first() in current_user.roles:
            # 超级管理员查看所有产品
            query = Product.query.order_by(Product.id.desc())
        else:
            # 普通用户只查看自己的产品
            query = Product.query.filter_by(user_id=current_user.id).order_by(
                Product.id.desc()
            )

        # 分页处理，捕获可能的数据库错误
        pagination = query.paginate(page=page, per_page=50, error_out=False)
        products = pagination.items
        new_products = [get_best_prices(product) for product in products]

        return render_template(
            "products/main_list.html", pagination=pagination, mains=new_products
        )
    except Exception as e:
        app.logger.error(f"Error in list_main: {str(e)}")
        flash("加载产品列表失败，请稍后重试", "danger")
        return render_template("products/main_list.html", pagination=None, mains=[])


@app.route("/main/add", methods=["GET", "POST"])
@login_required
def add_main():
    if not current_user.has_permission("add_product"):
        flash("您没有权限添加产品", "danger")
        return redirect(url_for("list_main", page=1))

    if request.method == "POST":
        url = request.form["url"].strip()
        try:
            if "\n" not in request.form["url"]:
                url = request.form["url"].strip()
                print(url)
                if url and "1688.com" in url:

                    @copy_current_request_context
                    def process_in_thread():
                        process_url_data(url, db, user_id=current_user.id)

                    thread = Thread(target=process_in_thread)
                    thread.start()
                    flash("正在处理 1688 URL，请稍后刷新查看", "info")
                    return render_template(
                        "products/main_form.html",
                        main=None,
                        loading=True,
                        users=User.query.filter_by(is_active=True).all(),
                    )
                new_product = Product(
                    url=url,
                    title=request.form["title"],
                    company_name=request.form["company_name"],
                    company_url=request.form["company_url"],
                    user_id=current_user.id,
                )
                db.session.add(new_product)
                db.session.commit()
                flash("产品添加成功", "success")
                return redirect(url_for("list_main", page=1))
            else:
                urls = [
                    url.strip()
                    for url in request.form["url"].split("\n")
                    if url.strip() and "1688.com" in url
                ]
                if urls:
                    for url in urls:
                        thread = Thread(
                            target=process_url_data, args=(url, db, current_user.id)
                        )
                        thread.start()
                    flash("批量处理 1688 URLs 已开始，请稍后刷新查看", "info")
                    return redirect(url_for("list_main", page=1))
                else:
                    new_product = Product(
                        url=request.form["url"],
                        title=request.form["title"],
                        company_name=request.form["company_name"],
                        company_url=request.form["company_url"],
                        user_id=current_user.id,
                    )
                    db.session.add(new_product)
                    db.session.commit()
                    flash("产品添加成功", "success")
                    return redirect(url_for("list_main", page=1))
        except Exception as e:
            db.session.rollback()
            app.logger.error(f"Error in add_main: {str(e)}")
            flash("添加产品失败，请检查输入或稍后重试", "danger")
            return redirect(url_for("list_main", page=1))

    return render_template(
        "products/main_form.html",
        main=None,
        loading=False,
        users=User.query.filter_by(is_active=True).all(),
    )


@app.route("/main/edit/<int:id>", methods=["GET", "POST"])
@login_required
def edit_main(id):
    product = Product.query.get_or_404(id)
    admin_role = Role.query.filter_by(name="超级管理员").first()

    if not current_user.has_permission("edit_product") or (
        product.user_id != current_user.id
        and not (admin_role and admin_role in current_user.roles)
    ):
        flash("您没有权限编辑此产品", "danger")
        return redirect(url_for("list_main", page=1))

    if request.method == "POST":
        try:
            product.url = request.form["url"]
            product.title = request.form["title"]
            product.company_name = request.form["company_name"]
            product.company_url = request.form["company_url"]
            if admin_role and admin_role in current_user.roles:
                user_id = request.form.get("user_id")
                if user_id:
                    product.user_id = int(user_id)
            db.session.commit()
            flash("产品更新成功", "success")
            return redirect(url_for("list_main", page=1))
        except Exception as e:
            db.session.rollback()
            app.logger.error(f"Error in edit_main: {str(e)}")
            flash("更新产品失败，请检查输入或稍后重试", "danger")
            return redirect(url_for("list_main", page=1))

    return render_template(
        "products/main_form.html",
        main=product,
        users=User.query.filter_by(is_active=True).all(),
    )


@app.route("/main/delete/<int:id>")
@login_required
def delete_main(id):
    product = Product.query.get_or_404(id)

    # 权限检查逻辑保持不变
    admin_role = Role.query.filter_by(name="超级管理员").first()
    if not current_user.has_permission("delete_product") or (
        product.user_id != current_user.id
        and not (admin_role and admin_role in current_user.roles)
    ):
        # 返回JSON格式的错误信息
        return jsonify({"status": "error", "message": "您没有权限删除此产品"}), 403

    try:
        db.session.delete(product)
        db.session.commit()
        return jsonify({"status": "success", "message": "产品删除成功"})
    except IntegrityError:
        db.session.rollback()
        return jsonify(
            {
                "status": "error",
                "message": "删除产品失败，购物车中有该产品，请先移除购物车中的产品",
            }
        ), 400


@app.route("/currencies", methods=["GET", "POST"])
@login_required
def list_currencies():
    if request.method == "POST" or request.headers.get("Accept") == "application/json":
        currencies = Currency.query.order_by(Currency.code).all()
        return jsonify(
            [
                {
                    "id": c.id,
                    "code": c.code,
                    "name_cn": c.name_cn,
                    "name_en": c.name_en,
                    "symbol": c.symbol,
                }
                for c in currencies
            ]
        )
    is_admin = current_user.has_role("超级管理员")
    currencies = Currency.query.order_by(Currency.id).all()
    return render_template(
        "currencies/list_currencies.html", currencies=currencies, is_admin=is_admin
    )


@app.route("/currencies/add", methods=["GET", "POST"])
@login_required
def add_currency():
    if not current_user.has_role("超级管理员"):
        flash("只有超级管理员可以添加货币", "danger")
        return redirect(url_for("list_currencies"))

    if request.method == "POST":
        try:
            currency = Currency(
                code=request.form["code"].strip().upper(),
                symbol=request.form["symbol"].strip(),
                name_cn=request.form["name_cn"].strip(),
                name_en=request.form["name_en"].strip(),
                name_local=request.form.get("name_local", "").strip(),
                is_active="is_active" in request.form,
            )
            db.session.add(currency)
            db.session.commit()
            flash("货币添加成功", "success")
            return redirect(url_for("list_currencies"))
        except Exception as e:
            db.session.rollback()
            flash(f"添加货币失败: {str(e)}", "danger")

    return render_template("currencies/currency_form.html", currency=None)


@app.route("/currencies/edit/<int:id>", methods=["GET", "POST"])
@login_required
def edit_currency(id):
    if not current_user.has_role("超级管理员"):
        flash("只有超级管理员可以编辑货币", "danger")
        return redirect(url_for("list_currencies"))

    currency = Currency.query.get_or_404(id)

    if request.method == "POST":
        try:
            currency.code = request.form["code"].strip().upper()
            currency.symbol = request.form["symbol"].strip()
            currency.name_cn = request.form["name_cn"].strip()
            currency.name_en = request.form["name_en"].strip()
            currency.name_local = request.form.get("name_local", "").strip()
            currency.is_active = "is_active" in request.form
            db.session.commit()
            flash("货币更新成功", "success")
            return redirect(url_for("list_currencies"))
        except Exception as e:
            db.session.rollback()
            flash(f"更新货币失败: {str(e)}", "danger")

    return render_template("currencies/currency_form.html", currency=currency)


@app.route("/currencies/delete/<int:id>")
@login_required
def delete_currency(id):
    if not current_user.has_role("超级管理员"):
        flash("只有超级管理员可以删除货币", "danger")
        return redirect(url_for("list_currencies"))

    currency = Currency.query.get_or_404(id)
    try:
        db.session.delete(currency)
        db.session.commit()
        flash("货币删除成功", "success")
    except Exception as e:
        db.session.rollback()
        flash(f"删除货币失败: {str(e)}", "danger")

    return redirect(url_for("list_currencies"))


# Exchange Rate routes
@app.route("/exchange_rates")
@login_required
def list_exchange_rates():
    rates = ExchangeRate.query.order_by(ExchangeRate.collected_date.desc()).all()
    currencies = Currency.query.filter_by(is_active=True).order_by(Currency.code).all()
    is_admin = current_user.has_role("超级管理员")
    return render_template(
        "currencies/list_exchange_rates.html",
        rates=rates,
        currencies=currencies,
        is_admin=is_admin,
    )


@app.route("/api/exchange_rate/<currency_code>")
@login_required
def get_today_exchange_rate(currency_code):
    # 查找目标货币
    currency = Currency.query.filter_by(code=currency_code.upper()).first()
    if not currency:
        return jsonify({"success": False, "message": "货币未找到"}), 404

    # 获取指定货币的最新汇率记录
    latest_exchange_rate = (
        ExchangeRate.query.filter_by(currency_id=currency.id)
        .order_by(ExchangeRate.id.desc())
        .first()
    )

    if not latest_exchange_rate:
        return jsonify({"success": False, "message": "汇率未找到"}), 404
    print(latest_exchange_rate.rate)
    return jsonify(
        {
            "success": True,
            "currency": currency.code,
            "rate": str(latest_exchange_rate.rate),
            "base_currency": latest_exchange_rate.base_currency_code,
            "collected_date": latest_exchange_rate.collected_date.strftime("%Y-%m-%d"),
        }
    )


@app.route("/exchange_rates/add", methods=["GET", "POST"])
@login_required
def add_exchange_rate():
    if not current_user.has_role("超级管理员"):
        flash("只有超级管理员可以添加汇率", "danger")
        return redirect(url_for("list_exchange_rates"))

    if request.method == "POST":
        try:
            rate = ExchangeRate(
                currency_id=int(request.form["currency_id"]),
                base_currency_code=request.form["base_currency_code"].strip().upper(),
                rate=Decimal(request.form["rate"]),
                change_amount=Decimal(request.form["change_amount"])
                if request.form["change_amount"]
                else None,
                change_percent=Decimal(request.form["change_percent"])
                if request.form["change_percent"]
                else None,
                source=request.form.get("source", "").strip(),
                data_type=request.form.get("data_type", "").strip(),
                collected_date=datetime.strptime(
                    request.form["collected_date"], "%Y-%m-%d"
                ).date(),
            )
            db.session.add(rate)
            db.session.commit()
            flash("汇率添加成功", "success")
            return redirect(url_for("list_exchange_rates"))
        except Exception as e:
            db.session.rollback()
            flash(f"添加汇率失败: {str(e)}", "danger")

    currencies = Currency.query.filter_by(is_active=True).order_by(Currency.code).all()
    today = datetime.today().strftime("%Y-%m-%d")
    return render_template(
        "currencies/exchange_rate_form.html",
        rate=None,
        currencies=currencies,
        today=today,
    )


@app.route("/exchange_rates/edit/<int:id>", methods=["GET", "POST"])
@login_required
def edit_exchange_rate(id):
    if not current_user.has_role("超级管理员"):
        flash("只有超级管理员可以编辑汇率", "danger")
        return redirect(url_for("list_exchange_rates"))

    rate = ExchangeRate.query.get_or_404(id)

    if request.method == "POST":
        try:
            rate.currency_id = int(request.form["currency_id"])
            rate.base_currency_code = request.form["base_currency_code"].strip().upper()
            rate.rate = Decimal(request.form["rate"])
            rate.change_amount = (
                Decimal(request.form["change_amount"])
                if request.form["change_amount"]
                else None
            )
            rate.change_percent = (
                Decimal(request.form["change_percent"])
                if request.form["change_percent"]
                else None
            )
            rate.source = request.form.get("source", "").strip()
            rate.data_type = request.form.get("data_type", "").strip()
            rate.collected_date = datetime.strptime(
                request.form["collected_date"], "%Y-%m-%d"
            ).date()
            db.session.commit()
            flash("汇率更新成功", "success")
            return redirect(url_for("list_exchange_rates"))
        except Exception as e:
            db.session.rollback()
            flash(f"更新汇率失败: {str(e)}", "danger")

    currencies = Currency.query.filter_by(is_active=True).order_by(Currency.code).all()
    return render_template(
        "currencies/exchange_rate_form.html", rate=rate, currencies=currencies
    )


@app.route("/exchange_rates/delete/<int:id>")
@login_required
def delete_exchange_rate(id):
    if not current_user.has_role("超级管理员"):
        flash("只有超级管理员可以删除汇率", "danger")
        return redirect(url_for("list_exchange_rates"))

    rate = ExchangeRate.query.get_or_404(id)
    try:
        db.session.delete(rate)
        db.session.commit()
        flash("汇率删除成功", "success")
    except Exception as e:
        db.session.rollback()
        flash(f"删除汇率失败: {str(e)}", "danger")

    return redirect(url_for("list_exchange_rates"))


@app.route("/company/add", methods=["GET", "POST"])
@login_required
def add_company():
    is_admin = current_user.has_permission("admin")  # 管理员权限判断

    # 检查用户是否有添加公司的权限
    if not current_user.has_permission("add_company"):
        flash("您没有权限添加公司", "danger")
        return redirect(url_for("list_companies"))

    if request.method == "POST":
        company = Company(
            name_cn=request.form["name_cn"],
            name_en=request.form["name_en"],
            address_cn=request.form["address_cn"],
            address_en=request.form["address_en"],
            website=request.form["website"],
        )
        db.session.add(company)
        db.session.commit()
        return redirect(url_for("list_companies"))
    return render_template("company/add_company.html", is_admin=is_admin)


@app.route("/companies/edit/<int:company_id>", methods=["GET", "POST"])
def edit_company(company_id):
    is_admin = current_user.has_permission("admin")  # 管理员权限判断
    if not is_admin:
        flash("您没有权限编辑公司", "danger")
        return redirect(url_for("list_companies"))

    company = Company.query.get_or_404(company_id)

    if request.method == "POST":
        # 获取表单数据
        company.name_cn = request.form.get("name_cn")
        company.name_en = request.form.get("name_en")
        company.address_cn = request.form.get("address_cn")
        company.address_en = request.form.get("address_en")
        company.website = request.form.get("website")

        # 验证必填字段
        if not all(
            [
                company.name_cn,
                company.name_en,
                company.address_cn,
                company.address_en,
                company.website,
            ]
        ):
            flash("所有字段都是必填的", "error")
            return redirect(url_for("edit_company", company_id=company_id))

        try:
            db.session.commit()
            flash("公司信息更新成功!", "success")
            return redirect(url_for("list_companies"))
        except Exception as e:
            db.session.rollback()
            flash(f"更新公司信息失败: {str(e)}", "error")
            return redirect(url_for("edit_company", company_id=company_id))

    # GET请求，显示编辑表单
    return render_template("company/add_company.html", company=company, is_edit=True)


@app.route("/companies/delete/<int:company_id>", methods=["POST"])
def delete_company(company_id):
    is_admin = current_user.has_permission("admin")  # 管理员权限判断
    if not is_admin:
        flash("您没有权限删除公司", "danger")
        return redirect(url_for("list_companies"))

    company = Company.query.get_or_404(company_id)

    try:
        db.session.delete(company)
        db.session.commit()
        flash("公司删除成功!", "success")
    except Exception as e:
        db.session.rollback()
        flash(f"删除公司失败: {str(e)}", "error")

    return redirect(url_for("list_companies"))


@app.route("/companies", methods=["GET", "POST"])
@login_required
def list_companies():
    is_admin = current_user.has_permission("admin")  # 管理员权限判断
    if request.method == "POST" or request.headers.get("Accept") == "application/json":
        companies = Company.query.all()
        return jsonify(
            [
                {"id": c.id, "name_cn": c.name_cn, "name_en": c.name_en}
                for c in companies
            ]
        )
    else:
        companies = Company.query.all()
        return render_template(
            "company/list_companies.html", companies=companies, is_admin=is_admin
        )


@app.route("/salespersons/add", methods=["GET", "POST"])
@login_required
def add_salesperson():
    # 检查用户是否有添加销售员的权限
    if not current_user.has_permission("add_salesperson"):
        flash("您没有权限添加销售员", "danger")
        return redirect(url_for("list_salespersons"))

    if request.method == "POST":
        username = request.form["username"].strip()
        password_plain = request.form["password"].strip()
        if not username or not password_plain:
            flash("用户名和密码不能为空", "danger")
            return redirect(url_for("add_salesperson"))

        salesperson = User(
            username=username,
            password_hash=generate_password_hash(password_plain),
            name_cn=request.form["name_cn"],
            name_en=request.form["name_en"],
            phone=request.form["phone"],
            email=request.form["email"],
            wechat=request.form.get("wechat") or None,
            whatsapp=request.form.get("whatsapp") or None,
            facebook=request.form.get("facebook") or None,
            instagram=request.form.get("instagram") or None,
            tiktok=request.form.get("tiktok") or None,
            twitter=request.form.get("twitter") or None,
        )
        sales_role = Role.query.filter_by(name="销售员").first()
        if sales_role:
            salesperson.roles.append(sales_role)

        db.session.add(salesperson)
        db.session.commit()
        flash("销售员已添加", "success")
        return redirect(url_for("list_salespersons"))
    return render_template("users/add_salesperson.html")


@app.route("/salespersons/edit/<int:id>", methods=["GET", "POST"])
@login_required  # 确保用户已登录（未登录用户会被flask-login拦截）
def edit_salesperson(id):
    # 获取目标用户对象
    salesperson = User.query.get_or_404(id)

    # 核心安全检查：
    # 1. 普通用户只能编辑自己的信息（id匹配当前登录用户）
    # 2. 管理员/有权限的用户可以编辑所有信息
    is_admin = current_user.has_permission("admin")  # 管理员权限判断
    is_self = current_user.id == salesperson.id  # 自身信息判断

    # 既不是管理员，也不是编辑自己的信息 → 拒绝访问
    if not (is_admin or is_self):
        flash("您没有权限编辑该用户的信息", "danger")
        return redirect(url_for("list_salespersons"))

    # 获取所有角色（用于表单选择）
    roles = Role.query.all()

    if request.method == "POST":
        # 进一步限制：普通用户不能修改角色（只有管理员可以）
        if not is_admin:
            # 强制使用当前用户的角色（忽略表单提交的角色数据）
            role_ids = [role.id for role in current_user.roles]
        else:
            role_ids = request.form.getlist("roles")

        # 基本信息更新
        salesperson.username = request.form.get("username").strip()
        salesperson.name_cn = request.form.get("name_cn").strip()
        salesperson.name_en = request.form.get("name_en").strip()
        salesperson.phone = request.form.get("phone").strip()
        salesperson.email = request.form.get("email").strip()
        salesperson.wechat = request.form.get("wechat").strip() or None
        salesperson.google = request.form.get("google").strip() or None
        salesperson.gmail = request.form.get("gmail").strip() or None
        salesperson.youtube = request.form.get("youtube").strip() or None
        salesperson.whatsapp = request.form.get("whatsapp").strip() or None
        salesperson.facebook = request.form.get("facebook").strip() or None
        salesperson.instagram = request.form.get("instagram").strip() or None
        salesperson.tiktok = request.form.get("tiktok").strip() or None
        salesperson.twitter = request.form.get("twitter").strip() or None
        salesperson.pinterest = request.form.get("pinterest").strip() or None

        # 处理密码更新（留空则不修改）
        password = request.form.get("password").strip()
        if password:
            salesperson.set_password(password)

        # 处理角色更新（已通过is_admin限制）
        salesperson.roles = Role.query.filter(Role.id.in_(role_ids)).all()

        # 处理激活状态（普通用户不能修改自己的激活状态）
        if is_admin:
            salesperson.is_active = "is_active" in request.form
        # 普通用户提交时忽略is_active字段，保持原有状态

        try:
            db.session.commit()
            flash("销售员信息已更新", "success")
            return redirect(url_for("list_salespersons"))
        except Exception as e:
            db.session.rollback()
            flash(f"更新失败: {str(e)}", "danger")

    return render_template(
        "users/edit_salesperson.html",
        salesperson=salesperson,
        roles=roles,
        is_admin=is_admin,
    )


@app.route("/salespersons", methods=["GET", "POST"])
@login_required
def list_salespersons():
    is_admin = current_user.has_permission("admin")
    if is_admin:
        salespersons = User.query.all()
    else:
        salespersons = [current_user]

    if request.method == "POST" or request.headers.get("Accept") == "application/json":
        return jsonify(
            [{"id": u.id, "name": u.name_cn or u.username} for u in salespersons]
        )
    return render_template(
        "users/list_salespersons.html", salespersons=salespersons, is_admin=is_admin
    )


@app.route("/details/<int:product_id>")
@login_required
def list_details(product_id):
    product = Product.query.get_or_404(product_id)

    # 检查用户是否是产品拥有者或超级管理员
    admin_role = Role.query.filter_by(name="超级管理员").first()
    if product.user_id != current_user.id and not (
        admin_role and admin_role in current_user.roles
    ):
        flash("您没有权限查看此产品详情", "danger")
        return redirect(url_for("list_main"))

    details = ProductDetail.query.filter_by(product_id=product_id).all()

    for detail in details:
        # 处理库存数据
        if detail.stock is not None:
            try:
                stock_decimal = Decimal(str(detail.stock))
                detail.stock_str = str(
                    stock_decimal.to_integral_value()
                    if stock_decimal == stock_decimal.to_integral_value()
                    else stock_decimal.normalize()
                )
            except InvalidOperation:
                detail.stock_str = "格式错误"
        else:
            detail.stock_str = "无数据"

        # 优先使用本地图片
        if detail.local_image_path:
            # 1. 拼接完整本地路径（static + 数据库存储的images/图片名）
            full_local_path = os.path.join(
                current_app.root_path, "static", detail.local_image_path
            )
            # 2. 检查文件是否存在
            if os.path.exists(full_local_path):
                # 3. 生成正确的URL（使用url_for确保路径格式正确）
                detail.display_image_url = url_for(
                    "static", filename=detail.local_image_path
                )
            else:
                # 文件不存在时使用远程URL
                detail.display_image_url = detail.image_url
        else:
            # 无本地图片时使用远程URL
            detail.display_image_url = detail.image_url

        # 构造阶梯价格数据列表
        price_ranges = []
        for wp in sorted(detail.wholesale_prices, key=lambda x: x.min_quantity):
            if wp.max_quantity is not None:
                range_text = f"{wp.min_quantity} - {wp.max_quantity}"
            else:
                range_text = f"≥ {wp.min_quantity}"
            price_ranges.append({"range": range_text, "price": wp.price})
        detail.price_ranges = price_ranges

    return render_template("products/details_list.html", main=product, details=details)


@app.route("/details/add/<int:product_id>", methods=["GET", "POST"])
@login_required
def add_details(product_id):
    product = Product.query.get_or_404(product_id)

    # 检查用户是否有添加详情的权限且是产品拥有者或超级管理员
    admin_role = Role.query.filter_by(name="超级管理员").first()
    if not current_user.has_permission("add_product_detail") or (
        product.user_id != current_user.id
        and not (admin_role and admin_role in current_user.roles)
    ):
        flash("您没有权限添加产品详情", "danger")
        return redirect(url_for("list_details", product_id=product_id))

    if request.method == "POST":
        stock_input = request.form["stock"]
        stock = float(stock_input) if stock_input else None

        new_detail = ProductDetail(
            product_id=product_id,
            other_model=request.form["other_model"],
            self_model=request.form["self_model"],
            price=float(request.form["price"]),
            image_url=request.form["image_url"],
            stock=stock,
        )
        db.session.add(new_detail)
        db.session.commit()
        flash("产品详情添加成功", "success")
        return redirect(url_for("list_details", product_id=product_id))
    return render_template("products/details_form.html", main=product, detail=None)


# 添加允许的文件类型检查函数
def allowed_file(filename):
    return "." in filename and filename.rsplit(".", 1)[1].lower() in {
        "png",
        "jpg",
        "jpeg",
        "gif",
    }


@app.route("/details/edit/<int:id>", methods=["GET", "POST"])
@login_required
def edit_details(id):
    detail = ProductDetail.query.get_or_404(id)

    # 检查用户是否有编辑详情的权限且是产品拥有者或超级管理员
    admin_role = Role.query.filter_by(name="超级管理员").first()
    if not current_user.has_permission("edit_product_detail") or (
        detail.product.user_id != current_user.id
        and not (admin_role and admin_role in current_user.roles)
    ):
        flash("您没有权限编辑产品详情", "danger")
        return redirect(url_for("list_details", product_id=detail.product_id))

    original_image_url = detail.image_url  # 保存原始URL用于比较

    if request.method == "POST":
        detail.other_model = request.form["other_model"]
        detail.self_model = request.form["self_model"]
        detail.price = float(request.form["price"])
        detail.image_url = request.form["image_url"]
        detail.local_image_path = request.form["local_image_path"]
        stock_input = request.form["stock"]
        detail.stock = float(stock_input) if stock_input else 0
        detail.description = request.form["description"]
        detail.description_en = request.form["description_en"]
        # 处理文件上传
        if "image_file" in request.files:
            file = request.files["image_file"]
            if file.filename != "":
                # 确保上传的是图片
                if file and allowed_file(file.filename):
                    # 删除旧的本地图片（如果存在）
                    if detail.local_image_path:
                        old_path = os.path.join(
                            current_app.static_folder,
                            detail.local_image_path,  # 现在直接存储相对路径，不需要替换static/
                        )
                        try:
                            if os.path.exists(old_path):
                                os.remove(old_path)
                        except Exception as e:
                            flash(f"删除旧图片时出错: {str(e)}", "warning")

                    # 生成安全的文件名
                    filename = secure_filename(file.filename)
                    # 添加唯一前缀避免冲突
                    unique_prefix = f"{detail.id}_{int(time.time())}_"
                    filename = unique_prefix + filename

                    # 确保images目录存在
                    images_dir = os.path.join(current_app.static_folder, "images")
                    os.makedirs(images_dir, exist_ok=True)

                    # 保存文件
                    filepath = os.path.join(images_dir, filename)
                    file.save(filepath)

                    # 更新数据库中的路径（只存储相对路径）
                    detail.local_image_path = f"images/{filename}"

                    flash("图片上传成功", "success")
                else:
                    flash("只允许上传图片文件(JPG, PNG, GIF)", "danger")

        # 检查image_url是否被修改
        if detail.image_url != original_image_url and detail.image_url:
            try:
                error_msg = download_single_image(detail)
                if error_msg:
                    flash(error_msg, "error")
            except Exception as e:
                flash(f"图片下载出错: {str(e)}", "error")

        db.session.commit()
        flash("产品详情更新成功", "success")
        return redirect(url_for("list_details", product_id=detail.product_id))

    return render_template(
        "products/details_form.html", main=detail.product, detail=detail
    )


@app.route("/details/batch_edit", methods=["POST"])
@login_required
def batch_edit_details():
    app.logger.info("📥 [批量编辑] 请求已到达 /details/batch_edit")

    # 用户信息
    app.logger.info(f"👤 当前用户: {current_user.username}, ID: {current_user.id}")

    # 权限检查
    admin_role = Role.query.filter_by(name="超级管理员").first()
    has_permission = current_user.has_permission("edit_product_detail")
    is_admin = admin_role and admin_role in current_user.roles

    app.logger.info(
        f"🔐 权限检查 => has_permission: {has_permission}, is_admin: {is_admin}"
    )

    if not has_permission and not is_admin:
        app.logger.warning("❌ 权限不足，拒绝访问")
        return jsonify({"success": False, "message": "您没有权限批量编辑产品详情"}), 403

    # 请求体内容
    try:
        edit_data = request.get_json()
        app.logger.info(
            f"📦 接收到的数据: {json.dumps(edit_data, ensure_ascii=False, indent=2)}"
        )
    except Exception as e:
        app.logger.error(f"❌ JSON解析失败: {str(e)}")
        return jsonify({"success": False, "message": "请求数据格式错误"}), 400

    if not edit_data:
        app.logger.warning("⚠️ 没有提供任何数据")
        return jsonify({"success": False, "message": "没有提供数据"}), 400

    try:
        updated_count = 0

        for item in edit_data:
            detail_id = item.get("id")
            app.logger.debug(f"🔍 正在处理 detail_id: {detail_id}")

            if not detail_id:
                app.logger.warning("🚫 跳过无效 ID")
                continue

            detail = ProductDetail.query.get(detail_id)
            if not detail:
                app.logger.warning(f"⚠️ 未找到 detail_id: {detail_id}")
                continue

            # 检查所属权限
            if detail.product.user_id != current_user.id and not is_admin:
                app.logger.warning(f"⛔️ 无权限修改产品 ID: {detail_id}")
                continue

            # 更新字段并打印变化
            before = {
                "self_model": detail.self_model,
                "description": detail.description,
                "description_en": detail.description_en,
            }

            if "self_model" in item:
                detail.self_model = item["self_model"]
            if "description" in item:
                detail.description = item["description"]
            if "description_en" in item:
                detail.description_en = item["description_en"]

            after = {
                "self_model": detail.self_model,
                "description": detail.description,
                "description_en": detail.description_en,
            }

            updated_count += 1
            app.logger.info(f"✅ 已更新 ID {detail_id}: {before} => {after}")

        db.session.commit()
        app.logger.info(f"🎉 批量更新完成，共更新 {updated_count} 条记录")

        return jsonify(
            {"success": True, "message": f"批量更新成功，共更新 {updated_count} 条记录"}
        )

    except Exception as e:
        db.session.rollback()
        app.logger.exception(f"❗️ 批量编辑过程中发生异常: {str(e)}")
        return jsonify({"success": False, "message": "更新过程中发生错误"}), 500


# @login_required 自动编号暂时不设置登录权限


@app.route("/details/auto_number/<int:id>", methods=["GET", "POST"])
def auto_number_details(id):
    detail = ProductDetail.query.get_or_404(id)

    # # 检查用户是否有自动编号的权限且是产品拥有者
    # if (
    #     not current_user.has_permission("edit_product_detail")
    #     or detail.product.user_id != current_user.id
    # ):
    #     flash("您没有权限执行自动编号", "danger")
    #     return redirect(url_for("list_details", product_id=detail.product_id))

    default_data = {"prefix": "", "increment": 1, "digits": 1, "start_number": 1}

    if request.method == "POST":
        prefix = request.form.get("prefix", "").strip()
        increment = int(request.form.get("increment", 1))
        digits = int(request.form.get("digits", 2))
        start_number = int(request.form.get("start_number", 1))

        if not prefix:
            flash("请输入前缀", "error")
            return redirect(url_for("auto_number_details", id=id))

        try:
            details = (
                ProductDetail.query.filter_by(product_id=detail.product_id)
                .order_by(ProductDetail.id)
                .all()
            )
            current_number = start_number

            for detail_item in details:
                new_code = f"{prefix}{str(current_number).zfill(digits)}"
                detail_item.self_model = new_code
                current_number += increment

            db.session.commit()
            flash(
                f"已成功为{len(details)}条记录生成顺序编号，从{start_number}开始",
                "success",
            )
            return redirect(url_for("list_details", product_id=detail.product_id))

        except Exception as e:
            db.session.rollback()
            flash(f"生成失败: {str(e)}", "error")
            return redirect(url_for("auto_number_details", id=id))

    preview_value = f"{default_data['prefix']}{str(default_data['start_number']).zfill(default_data['digits'])}"

    return render_template(
        "products/auto_number.html",
        detail=detail,
        defaults=default_data,
        preview_value=preview_value,
    )


@app.route("/details/delete/<int:id>")
@login_required
def delete_details(id):
    detail = ProductDetail.query.get_or_404(id)

    # 检查用户是否有删除详情的权限且是产品拥有者或超级管理员
    admin_role = Role.query.filter_by(name="超级管理员").first()
    if not current_user.has_permission("delete_product_detail") or (
        detail.product.user_id != current_user.id
        and not (admin_role and admin_role in current_user.roles)
    ):
        flash("您没有权限删除产品详情", "danger")
        return redirect(url_for("list_details", product_id=detail.product_id))

    product_id = detail.product_id
    db.session.delete(detail)
    db.session.commit()
    flash("产品详情删除成功", "success")
    return redirect(url_for("list_details", product_id=product_id))


@app.route("/search")
@login_required
def search():
    query = request.args.get("q", "").strip()
    results = []
    admin_role = Role.query.filter_by(name="超级管理员").first()

    logger.info(f"搜索请求 - 用户: {current_user.id}, 查询词: '{query}'")

    if query:
    #     if admin_role and admin_role in current_user.roles:
    #         # 超级管理员搜索所有产品
    #         product_results = (
    #             Product.query.filter(
    #                 db.or_(
    #                     Product.title.ilike(f"%{query}%"),
    #                     Product.company_name.ilike(f"%{query}%"),
    #                 )
    #             )
    #             .options(db.joinedload(Product.details))
    #             .all()
    #         )
    #         logger.info(f"超级管理员搜索 - 产品匹配数: {len(product_results)}")

    #         detail_results = (
    #             ProductDetail.query.filter(
    #                 db.or_(
    #                     ProductDetail.other_model.ilike(f"%{query}%"),
    #                     ProductDetail.self_model.ilike(f"%{query}%"),
    #                     ProductDetail.description.ilike(f"%{query}%"),
    #                     ProductDetail.description_en.ilike(f"%{query}%"),
    #                 )
    #             )
    #             .join(Product)
    #             .options(db.joinedload(ProductDetail.product))
    #             .all()
    #         )
    #         logger.info(f"超级管理员搜索 - 详情匹配数: {len(detail_results)}")
    #     else:
    #         # 普通用户只搜索自己的产品
    #         product_results = (
    #             Product.query.filter(
    #                 db.or_(
    #                     Product.title.ilike(f"%{query}%"),
    #                     Product.company_name.ilike(f"%{query}%"),
    #                 ),
    #                 Product.user_id == current_user.id,
    #             )
    #             .options(db.joinedload(Product.details))
    #             .all()
    #         )
    #         logger.info(f"普通用户搜索 - 产品匹配数: {len(product_results)}")

    #         detail_results = (
    #             ProductDetail.query.filter(
    #                 db.or_(
    #                     ProductDetail.other_model.ilike(f"%{query}%"),
    #                     ProductDetail.self_model.ilike(f"%{query}%"),
    #                     ProductDetail.description.ilike(f"%{query}%"),
    #                     ProductDetail.description_en.ilike(f"%{query}%"),
    #                 )
    #             )
    #             .join(Product)
    #             .filter(Product.user_id == current_user.id)
    #             .options(db.joinedload(ProductDetail.product))
    #             .all()
    #         )
    #         logger.info(f"普通用户搜索 - 详情匹配数: {len(detail_results)}")
        product_results = (
            Product.query.filter(
                db.or_(
                    Product.title.ilike(f"%{query}%"),
                    Product.company_name.ilike(f"%{query}%"),
                )
            )
            .options(db.joinedload(Product.details))
            .all()
        )
        logger.info(f"超级管理员搜索 - 产品匹配数: {len(product_results)}")

        detail_results = (
            ProductDetail.query.filter(
                db.or_(
                    ProductDetail.other_model.ilike(f"%{query}%"),
                    ProductDetail.self_model.ilike(f"%{query}%"),
                    ProductDetail.description.ilike(f"%{query}%"),
                    ProductDetail.description_en.ilike(f"%{query}%"),
                )
            )
            .join(Product)
            .options(db.joinedload(ProductDetail.product))
            .all()
        )
        # 处理产品结果中的图片URL
        for product in product_results:
            for detail in product.details:
                image_log_base = f"产品ID: {product.id}, 详情ID: {detail.id}"

                # 库存处理
                if detail.stock is not None:
                    try:
                        stock_decimal = Decimal(str(detail.stock))
                        detail.stock_str = str(
                            stock_decimal.to_integral_value()
                            if stock_decimal == stock_decimal.to_integral_value()
                            else stock_decimal.normalize()
                        )
                    except InvalidOperation:
                        detail.stock_str = "格式错误"
                        logger.warning(
                            f"{image_log_base} - 库存格式错误: {detail.stock}"
                        )
                else:
                    detail.stock_str = "无数据"
                    logger.debug(f"{image_log_base} - 库存无数据")

                # 图片URL处理
                detail.display_image_url = None  # 初始化
                if detail.local_image_path:
                    try:
                        detail.display_image_url = url_for(
                            "static", filename=detail.local_image_path
                        )
                        logger.bind(
                            product_id=product.id,
                            detail_id=detail.id,
                            image_type="local",
                        ).info(
                            f"本地图片URL生成成功: {detail.display_image_url} (本地路径: {detail.local_image_path})"
                        )
                    except Exception as e:
                        logger.bind(
                            product_id=product.id,
                            detail_id=detail.id,
                            image_type="local",
                        ).error(
                            f"本地图片URL生成失败: {str(e)} (本地路径: {detail.local_image_path})"
                        )
                else:
                    if detail.image_url:
                        detail.display_image_url = detail.image_url
                        logger.bind(
                            product_id=product.id,
                            detail_id=detail.id,
                            image_type="remote",
                        ).info(f"使用远程图片URL: {detail.image_url}")
                    else:
                        logger.bind(product_id=product.id, detail_id=detail.id).warning(
                            "无可用图片URL"
                        )

                results.append(
                    {"main": product, "detail": detail, "match_type": "main"}
                )

        # 处理详情结果中的图片URL
        for detail in detail_results:
            image_log_base = f"产品ID: {detail.product.id}, 详情ID: {detail.id}"

            # 检查是否已在结果中
            if not any(r["detail"].id == detail.id for r in results):
                # 库存处理
                if detail.stock is not None:
                    try:
                        stock_decimal = Decimal(str(detail.stock))
                        detail.stock_str = str(
                            stock_decimal.to_integral_value()
                            if stock_decimal == stock_decimal.to_integral_value()
                            else stock_decimal.normalize()
                        )
                    except InvalidOperation:
                        detail.stock_str = "格式错误"
                        logger.warning(
                            f"{image_log_base} - 库存格式错误: {detail.stock}"
                        )
                else:
                    detail.stock_str = "无数据"
                    logger.debug(f"{image_log_base} - 库存无数据")

                # 图片URL处理
                detail.display_image_url = None  # 初始化
                if detail.local_image_path:
                    try:
                        detail.display_image_url = url_for(
                            "static", filename=detail.local_image_path
                        )
                        logger.bind(
                            product_id=detail.product.id,
                            detail_id=detail.id,
                            image_type="local",
                        ).info(
                            f"本地图片URL生成成功: {detail.display_image_url} (本地路径: {detail.local_image_path})"
                        )
                    except Exception as e:
                        logger.bind(
                            product_id=detail.product.id,
                            detail_id=detail.id,
                            image_type="local",
                        ).error(
                            f"本地图片URL生成失败: {str(e)} (本地路径: {detail.local_image_path})"
                        )
                else:
                    if detail.image_url:
                        detail.display_image_url = detail.image_url
                        logger.bind(
                            product_id=detail.product.id,
                            detail_id=detail.id,
                            image_type="remote",
                        ).info(f"使用远程图片URL: {detail.image_url}")
                    else:
                        logger.bind(
                            product_id=detail.product.id, detail_id=detail.id
                        ).warning("无可用图片URL")

                results.append(
                    {"main": detail.product, "detail": detail, "match_type": "detail"}
                )
            else:
                logger.bind(product_id=detail.product.id, detail_id=detail.id).debug(
                    "记录已在结果中，跳过"
                )

    logger.info(f"搜索结果 - 总结果数: {len(results)}")
    return render_template("search/search_results.html", results=results, query=query)


@app.route("/export", methods=["GET"])
@login_required
def export_page():
    return render_template("export.html")


def start_app():
    with app.app_context():
        db.create_all()
        # init_currencies()  # 如果你需要初始化币种

        # ✅ 启动时执行一次
        logger.info("💡 启动时执行一次爬虫任务")
        check_and_crawl()
        logger.info("✅ APScheduler 启动成功")

    debug = config("DEBUG", cast=bool, default=False)
    app.run(debug=debug, port=1000, host="0.0.0.0")


if __name__ == "__main__":
    logger.info("🚀 Flask 正在启动...")
    start_app()
